﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ProjetSMA.Model
{
    public class Graph
    {
        private List<GenericNode> m_etat; //la liste complète des états, c’est-à-dire des GenericNode 
        private List<GenericNode> m_nodeVisited; //liste des noeuds visités, liste des fermés
        private List<GenericNode> m_nodeNotVisited; //liste des noeuds non visités, liste des ouverts

        public Graph()
        {
            m_nodeNotVisited = new List<GenericNode>();
            m_nodeVisited = new List<GenericNode>();
            m_etat = new List<GenericNode>();
        }
        public GenericNode RechercheSolutionAEtoile(GenericNode N0)//retourne le nœud état final ; NB : le chemin solution peut être obtenu à l’aide du parent de chaque nœud.
        {
            GenericNode N = N0;
            while (N != null && !N.EndState())
            {
                MAJSuccesseurs(N);
                /*Console.WriteLine("Avant test ListNodNotVisited");
                for (int i = 0; i < m_nodeNotVisited.Count; i++)
                {
                    Console.WriteLine("Name: " + m_nodeNotVisited[i].NomNoeud);
                }*/
                try
                {
                    N = m_nodeNotVisited[0];
                }
                catch (Exception e)
                {
                    N = null;
                }
            }
            return N;
        }

        public void MAJSuccesseurs(GenericNode N) //récupère la liste des nœuds successeurs grâce à GetListSucc, puis met à jour les chemins et la liste des fermés et des ouverts selon  l’algorithme Dijkstra/A*
        {
            m_nodeVisited.Add(N);
            m_nodeNotVisited.Remove(N);

           // Console.WriteLine("MajSuccesseurs");

            List<GenericNode> myList = N.GetListSucc();
            for (int i = 0; i < myList.Count(); i++)
            {
               // Console.WriteLine("Boucle For");
               // Console.WriteLine("Name Noeud: "+N.NomNoeud);
                if (!InListNode(m_nodeNotVisited, myList[i]) && !InListNode(m_nodeVisited, myList[i]))
                {
                    //Console.WriteLine("Premier IF");
                    m_nodeNotVisited.Add(myList[i]);
                    myList[i].Parent = N;
                    myList[i].MyCost = N.MyCost + 1; // a chaque déplacement, le coût réel augmente de un
                    myList[i].MyTotalCost = myList[i].MyCost + myList[i].GetArcCost();
                }
                else if (InListNode(m_nodeNotVisited, myList[i]))
                {
                   // Console.WriteLine("Elfe IF");
                    if (N.MyCost < FindNodeInList(myList[i]).MyTotalCost)
                    {
                       // Console.WriteLine("Deuxieme IF");
                        FindNodeInList(myList[i]).MyCost = myList[i].MyCost;
                        FindNodeInList(myList[i]).MyTotalCost = myList[i].MyCost + myList[i].GetArcCost();
                        FindNodeInList(myList[i]).Parent = N;
                    }
                }
            }

            m_nodeNotVisited.Sort(Compare);
           /* for (int i = 0; i < m_nodeNotVisited.Count; i++)
            {
                Console.WriteLine("List :" + m_nodeNotVisited[i].NomNoeud);
            }
            */
        }

        public int Compare(object x, object y)
        {
            GenericNode N1 = (GenericNode)x;
            GenericNode N2 = (GenericNode)y;

            if (N1.MyTotalCost < N2.MyTotalCost)
                return -1;
            else if (N1.MyTotalCost > N2.MyTotalCost)
                return 1;
            else return 0;
        }

        public bool InListNode(List<GenericNode> myList, GenericNode N)
        {
            bool test = false;
            int i = 0;
            while (test == false && i < myList.Count())
            {
                if (myList[i].NomNoeud == N.NomNoeud)
                    test = true;
                i++;
            }
            return test;
        }

        // attention : on considère que N est obligatoirement dans la liste _nodeNotVisited sinon ça plante
        public GenericNode FindNodeInList(GenericNode N)
        {
            int i = 0;
            int indice = 0;
            while (i < m_nodeNotVisited.Count() && indice == -1)
            {
                if (m_nodeNotVisited[i].NomNoeud == N.NomNoeud)
                    indice = i;
                i++;
            }
            return m_nodeVisited[indice];
        }
    }
}
